package com.ang.encrypt;

import org.bouncycastle.crypto.digests.SM3Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.pqc.math.linearalgebra.ByteUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.security.Security;
import java.util.Arrays;

/**
 * SM3加解密工具类
 * SM3(hash算法)与其它hash算法比较
 * 国际上通用的hash算法为SHA系列算法，MD4  MD5算法
 * SM3实在SHA-256基础上改进的算法
 */
public class SM3Util {

    private static final Logger log = LoggerFactory.getLogger(SM3Util.class.getSimpleName());
    private static final String ENCODING = "UTF-8";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 方式一:不提供密钥 Return
     *
     * @param paramStr 原文
     * @return 返加密后, 直定长度-32的16制字符串
     */
    public static String encrypt(String paramStr) {
        // 将返回的hash值转换成16进制字符串
        String resultHexString = "";
        try {
            // 将字符串转换byte数组
            byte[] srcData = paramStr.getBytes(ENCODING);
            // 调用hash()
            byte[] resultHash = hash(srcData);
            resultHexString = ByteUtils.toHexString(resultHash);
        } catch (UnsupportedEncodingException e) {
            log.error("SM3Util.encrypt error:{}", e.getMessage(), e);
        }
        return resultHexString;
    }

    /**
     * 返回长度为32位的byte数组
     *
     * @param srcData 原文二进制数据
     * @return 返回长度为32位的byte数组
     */
    public static byte[] hash(byte[] srcData) {
        SM3Digest digest = new SM3Digest();
        digest.update(srcData, 0, srcData.length);
        byte[] hash = new byte[digest.getDigestSize()];
        digest.doFinal(hash, 0);
        return hash;
    }

    /**
     * 通过秘钥进行加密
     *
     * @param key     秘钥
     * @param srcData 原文二进制数据
     * @return 密文二进制数据
     */
    public static byte[] hmac(byte[] key, byte[] srcData) {
        KeyParameter keyParameter = new KeyParameter(key);
        SM3Digest digest = new SM3Digest();
        HMac mac = new HMac(digest);
        mac.init(keyParameter);
        mac.update(srcData, 0, srcData.length);
        byte[] result = new byte[mac.getMacSize()];
        mac.doFinal(result, 0);
        return result;
    }

    /**
     * 校验
     *
     * @param srcStr       原文
     * @param sm3HexString sm3加密的16进制密文
     * @return 校验结果
     */
    public static boolean verify(String srcStr, String sm3HexString) {
        boolean flag = false;
        try {
            byte[] srcData = srcStr.getBytes(ENCODING);
            byte[] sm3Hash = ByteUtils.fromHexString(sm3HexString);
            byte[] newHash = hash(srcData);
            if (Arrays.equals(newHash, sm3Hash)) {
                flag = true;
            }
        } catch (UnsupportedEncodingException e) {
            log.error("SM3Util.verify error:{}", e.getMessage(), e);
        }
        return flag;
    }

    public static void main(String[] args) {
        String aa = "Aa123456";
        String hex = SM3Util.encrypt(aa);
        log.debug(">>>>>>>>>>>>>SM3Util.encrypt:{}", hex);
        log.debug(">>>>>>>>>>>>>SM3Util.verify:{}", SM3Util.verify(aa, hex));
    }
}
